
#include "StdAfx.h"
#include "VarBuffer.h"

CVarBuffer::CVarBuffer(int nSize)
: m_nSize(nSize)
{
	m_pBuf = new unsigned char[m_nSize];
	m_pRead = m_pBuf;
	m_pWrite = m_pBuf;
}

CVarBuffer::~CVarBuffer(void)
{
	if(m_pBuf)
	{
		delete [] m_pBuf;
		m_pBuf = NULL;
	}
}

int CVarBuffer::GetDataSize()
{
	return static_cast<int>((m_pWrite - m_pRead + m_nSize) % m_nSize);
}

int CVarBuffer::GetFreeSize()
{
	if(m_pRead == m_pWrite)
		return m_nSize;
	else
		return static_cast<int>((m_pRead - m_pWrite + m_nSize) % m_nSize);
}

BOOL CVarBuffer::Write(unsigned char* pWrite, unsigned long size)
{
	BOOL bHasFreeSpace = FALSE;
	m_cs.Lock();
	bHasFreeSpace = static_cast<unsigned long>(GetFreeSize()) > size;
	if(bHasFreeSpace)
	{
		unsigned long  nTailLen = static_cast<unsigned long>(m_nSize - (m_pWrite - m_pBuf));
		if(size > nTailLen)
		{
			memcpy(m_pWrite, pWrite, nTailLen);
			memcpy(m_pBuf, pWrite + nTailLen, size - nTailLen);
			m_pWrite = m_pBuf + size - nTailLen;
		}
		else
		{
			memcpy(m_pWrite, pWrite, size);
			m_pWrite += size;
		}
	}
#ifdef _DEBUG
	else
	{
		TRACE("failed: write len = %d, freesize = %d\n", size, GetFreeSize());
	}
#endif
	m_cs.Unlock();

	return bHasFreeSpace;
}

BOOL CVarBuffer::Read(unsigned char* pRead, unsigned long size)
{
	BOOL bHasEnoughData = FALSE;
	m_cs.Lock();
	bHasEnoughData = static_cast<unsigned long>(GetDataSize()) >= size;
	if(bHasEnoughData)
	{
		unsigned long nTailLen = static_cast<unsigned long>(m_nSize - (m_pRead - m_pBuf));
		if(nTailLen < size)
		{
			memcpy(pRead, m_pRead, nTailLen);
			memcpy(pRead + nTailLen, m_pBuf, size - nTailLen);
			m_pRead = m_pBuf + size - nTailLen;
		}
		else
		{
			memcpy(pRead, m_pRead, size);
			m_pRead += size;
		}
	}
	m_cs.Unlock();

	return bHasEnoughData;
}

BOOL CVarBuffer::TryRead(unsigned char* pRead, unsigned long size)
{
	BOOL bHasEnoughData = FALSE;
	m_cs.Lock();
	bHasEnoughData = static_cast<unsigned long>(GetDataSize()) >= size;
	if(bHasEnoughData)
	{
		unsigned long nTailLen = static_cast<unsigned long>(m_nSize - (m_pRead - m_pBuf));
		if(nTailLen < size)
		{
			memcpy(pRead, m_pRead, nTailLen);
			memcpy(pRead + nTailLen, m_pBuf, size - nTailLen);
		}
		else
		{
			memcpy(pRead, m_pRead, size);
		}
	}
	m_cs.Unlock();

	return bHasEnoughData;
}

void CVarBuffer::PurgeBuffer()
{
	m_cs.Lock();
	m_pRead = m_pBuf;
	m_pWrite = m_pBuf;
	m_cs.Unlock();
}